﻿using System;
using System.Runtime.Serialization;

namespace Helpers.Common
{
    [DataContract(Name = "ResponseWithDataOf{0}Type")]
    public class Response<DataType>
    {
        #region Properties

        [DataMember]
        public int ErrorCode { get; protected set; }
        [DataMember]
        public Exception Exception { get; protected set; }
        [DataMember]
        public bool Success { get; protected set; }
        [DataMember]
        public string Message { get; protected set; }
        [DataMember]
        public DataType Data { get; set; }

        #endregion

        public Response()
            : this(true, "", 0, default(DataType)) { }
        public Response(string message)
            : this(false, message, -1, default(DataType)) { }
        public Response(int errorCode)
            : this(false, "", errorCode, default(DataType)) { }
        public Response(DataType data)
            : this(true, "", 0, data) { }
        public Response(bool success, string message)
            : this(success, message, 0, default(DataType)) { }
        public Response(bool success, string message, int errorCode)
            : this(success, message, errorCode, default(DataType)) { }
        public Response(bool success, DataType data)
            : this(success, "", 0, data) { }
        public Response(bool success, string message, DataType data)
            : this(success, message, 0, data) { }
        public Response(bool success, string message, int errorCode, DataType data)
        {
            this.Data = data;
            this.ErrorCode = errorCode;
            this.Success = success;
            this.Message = message;
        }
        public Response(Exception ex)
            : this(false, "", -1, default(DataType))
        {
            this.FillWithException(ex);
        }
        public Response(Exception ex, string message)
            : this(false, message, -1, default(DataType))
        {
            this.FillWithException(ex);
        }
        public Response(Exception ex, string message, int errorCode)
            : this(false, message, errorCode, default(DataType))
        {
            this.FillWithException(ex);
        }

        #region Methods

        protected virtual void FillWithException(Exception ex)
        {
            this.Exception = ex;
        }
        public Response<DataType> ToJsonableResponse()
        {
            return new Response<DataType>(
                this.Success, 
                ((string.IsNullOrWhiteSpace(this.Message) == true) && (this.Exception != null))
                    ? this.Exception.Message
                    : this.Message,
                this.ErrorCode, 
                this.Data
            );
        }
        /// <summary>
        /// Returns an instance of the response base class. This method will be used to prevent issues when
        /// the object is serialized on the wcf service method with other type.
        /// </summary>
        /// <returns>An instance of the resposne base class.</returns>
        public virtual Response<DataType> ToResponse()
        {
            if (this.Exception == null)
                return new Response<DataType>(this.Success, this.Message, this.ErrorCode, this.Data);
            else
                return new Response<DataType>(this.Exception, this.Message, this.ErrorCode);
        }

        #endregion
    }

    [DataContract]
    public class Response : Response<object>
    {
        public Response()
            : base() { }
        public Response(string message)
            : base(message) { }
        public Response(int errorCode)
            : base(errorCode) { }
        public Response(object data)
            : base(data) { }
        public Response(bool success, string message)
            : base(success, message) { }
        public Response(bool success, string message, int errorCode)
            : base(success, message, errorCode) { }
        public Response(bool success, string message, object data)
            : base(success, message, data) { }
        public Response(bool success, string message, int errorCode, object data)
            : base(success, message, errorCode, data) { }
        public Response(Exception ex)
            : base(ex) {}
        public Response(Exception ex, string message)
            : base(ex, message) { }
        public Response(Exception ex, string message, int errorCode)
            : base(ex, message, errorCode) { }

        #region Methods

        /// <summary>
        /// Returns an instance of the response base class. This method will be used to prevent issues when
        /// the object is serialized on the wcf service method with other type.
        /// </summary>
        /// <returns>An instance of the resposne base class.</returns>
        public virtual Response ToResponse()
        {
            if (this.Exception == null)
                return new Response(this.Success, this.Message, this.ErrorCode, this.Data);
            else
                return new Response(this.Exception, this.Message, this.ErrorCode);
        }

        #endregion
    }
}